//
// Created by 11067 on 2023/3/7.
//
#include "api.h"
#include "OptionParser.h"
#include "Graph.h"
#include "utils/errors.h"
#include <cstring>
#include <sstream>
/**
 * 把C风格字符串转换为小写，我以为Graph转了
 * @param word 待转换字符串
 * @return word
 */
static void to_lower_case(std::string &word) {
    for (auto &c: word) {
        c |= (1 << 5);
    }
}
int gen_chain_word(char **words, int len, char **result, char head, char tail, char no_begin, bool enable_loop) {
    std::set<std::string> wordsVec;
    std::vector<std::string> chain;
    chain.reserve(128);
    //result = new char *[MAX_RESULT_SIZE];
    for (int i = 0; i < len; ++i) {
        std::string s{words[i]};
        to_lower_case(s);
        wordsVec.insert(s);
    }
    Graph graph(wordsVec);
    if (enable_loop) {
        graph.longest_chain_r(head, tail, no_begin, true, chain);
    } else {
        if (graph.has_cycle()) {
            ERR(APIException, "word list has cycle without specify `enable_loop(-r)`.");
#ifndef USE_EXCEPTION
            return 0;
#endif
        }
        graph.longest_chain(head, tail, no_begin, true, chain);
    }
    if (chain.size() > MAX_RESULT_SIZE) {
        ERR(APIException, "result too long.");
#ifndef USE_EXCEPTION
        return static_cast<int>(chain.size());
#endif
    }
    for (int i = 0; i < chain.size(); ++i) {
        result[i] = new char[chain[i].size() + 1];
        strcpy_s(result[i], chain[i].length() + 1, chain[i].c_str());
    }
    return static_cast<int>(chain.size());
}

int gen_chains_all(char **words, int len, char **result) {
    std::set<std::string> wordsVec;
    std::vector<std::vector<const std::string*>> chains;
    for (int i = 0; i < len; ++i) {
        std::string s{words[i]};
        to_lower_case(s);
        wordsVec.insert(s);
    }
    Graph graph(wordsVec);
    if (graph.has_cycle()) {
            ERR(APIException, "word list has cycle without specify `enable_loop(-r)`(-n not support).");
#ifndef USE_EXCEPTION
            return 0;
#endif
    }
    graph.cnt_chains(chains);
    if (chains.size() > MAX_RESULT_SIZE) {
        ERR(APIException, "result too long.");
#ifndef USE_EXCEPTION
        return static_cast<int>(chains.size());
#endif
    }
    for (int i = 0; i < chains.size(); ++i) {
        std::stringstream ss;
        for (auto s: chains[i]) {
            ss << *s << " ";
        }
        std::string chain = ss.str();
        result[i] = new char[chain.length() + 1];
        strcpy_s(result[i], chain.length() + 1,chain.c_str());
    }
    return static_cast<int>(chains.size());
}

//int gen_chain_word_unique(char **words, int len, char **result) {
//    std::set<std::string> wordsVec;
//    std::vector<std::vector<std::string>> chains;
//    //result = new char *[MAX_RESULT_SIZE];
//    for (int i = 0; i < len; ++i) {
//        wordsVec.insert(std::string(words[i]));
//    }
//    Graph graph(wordsVec);
//    if (graph.has_cycle()) {
//        return WORD_CIRCLE;
//    }
//    for (int i = 0; i < 26; i++) {
//        chains.emplace_back();
//        graph.longest_chain('\0', '\0', '\0', true, chains[i]);
//    }
//    if (chains.size() > MAX_RESULT_SIZE) {
//        return RESULT_TOO_LONG;
//    }
//    for (int i = 0; i < chains.size(); ++i) {
//        std::stringstream ss;
//        for (const auto& s: chains[i]) {
//            ss << s << " ";
//        }
//        std::string chain = ss.str();
//        result[i] = new char[chain.length() + 1];
//        strcpy_s(result[i], chain.length() + 1, chain.c_str());
//    }
//    return static_cast<int>(chains.size());
//}

int gen_chain_char(char **words, int len, char **result, char head, char tail, char no_begin, bool enable_loop) {
    std::set<std::string> wordsVec;
    std::vector<std::string> chain;
    chain.reserve(128);
    //result = new char *[MAX_RESULT_SIZE];
    for (int i = 0; i < len; ++i) {
        std::string s{words[i]};
        to_lower_case(s);
        wordsVec.insert(s);
    }
    Graph graph(wordsVec);
    if (enable_loop) {
        graph.longest_chain_r(head, tail, no_begin, false, chain);
    } else {
        if (graph.has_cycle()) {
            ERR(APIException, "word list has cycle without specify `enable_loop(-r)`.");
#ifndef USE_EXCEPTION
            return 0;
#endif
        }
        graph.longest_chain(head, tail, no_begin, false, chain);
    }
    if (chain.size() > MAX_RESULT_SIZE) {
        ERR(APIException, "result too long.");
#ifndef USE_EXCEPTION
        return static_cast<int>(chain.size());
#endif
    }
    for (int i = 0; i < chain.size(); ++i) {
        result[i] = new char[chain[i].size() + 1];
        strcpy_s(result[i], chain[i].length() + 1, chain[i].c_str());
    }
    // size <= 20000
    return static_cast<int>(chain.size());
}

int free_result(char **result, int len) {
    for (int i = 0; i < len; ++i) {
        delete [] result[i];
    }
    delete [] result;
    return 0;
}

char **alloc_result() {
    return new char *[MAX_RESULT_SIZE];
}

